#include "Arc2DHandler.h"
#include "CmdManager.h"
#include "SendPointHandlerBase.h"
#include "Scene.h"
#include "Ucs.h"
#include "Arc2D.h"
#include "qundostack.h"
#include "Operation/OpAdd.h"
#include "Arc2.h"
#include "Line2.h"
#include "QtOSGWidget.h"

Arc2DHandler::Arc2DHandler()
{
}

Arc2DHandler::~Arc2DHandler()
{
}

void Arc2DHandler::input(const QVariant& data, const QString& rawInput, CommandSource cs)
{
	auto sph = getSendPointHandler();
	auto scene = getScene();
	auto widget3D = getWidget();
	auto ucs = scene->getCurrentUCS();
	if (data.type() == QVariant::Bool/* && !data.toBool()*/)
	{
		if (m_arc)
		{
			widget3D->pauseRenderThread();
			ucs->removeChild(m_arc);
			widget3D->resumeRenderThread();
		}
		emit finished();
		return;
	}

	if (status() == 0)
	{
		if (sph)
		{
			sph->setPointMask(CS_LBTNDOWN);
		}
		m_arc = std::make_shared<Arc2D>(ucs.get());
		m_arc->setColor(ucs->getUCSColor());
		widget3D->pauseRenderThread();
		ucs->addChild(m_arc);
		widget3D->resumeRenderThread();
		cmdManager()->setPlane((Plane2DKind)ucs->getKind());
		prompt(1, tr("指定圆弧的起点:"));
		return;
	}

	if (status() == 1)
	{
		if (sph)
		{
			sph->setPointMask(CS_LBTNDOWN | CS_MOUSEMOVE);
		}
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_startPt = { ucspt.x(),ucspt.y(),ucspt.z() };
			setRubberLineP1(m_startPt);
			prompt(2, tr("指定圆弧的第二点或 [中心(C)/终点(E)]"));
		}
		return;
	}

	if (status() == 2)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_secondPt = ucspt;
			showRubberLine(true);
			setRubberLineP2(m_secondPt);
			if (cs != CS_MOUSEMOVE)
			{
				showRubberLine(false);
				prompt(3, tr("指定圆弧的终点:"));
			}
		}
		else if (rawInput == QString("C") || rawInput == QString("c"))
		{
			prompt(4, tr("指定圆弧的中心:"));
		}
		else if (rawInput == QString("E") || rawInput == QString("e"))
		{
			prompt(7, tr("指定圆弧的终点:"));
		}
		return;
	}
	//start - second - end
	if (status() == 3)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_endPt = ucspt;
			CArc2 arc(
				{ m_startPt.x(),m_startPt.y(),m_startPt.z() },
				{ m_secondPt.x(),m_secondPt.y(),m_secondPt.z() },
				{ m_endPt.x(),m_endPt.y(),m_endPt.z() }
			);
			m_arc->set(osg::Vec3d(arc.center.x,arc.center.y,0), arc.radius, arc.StartAngle(), arc.EndAngle());		
			if (cs != CS_MOUSEMOVE)
			{
				drawFinished(scene);
			}
		}
		return;
	}
	//start - center
	if (status() == 4)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			if (sph)
			{
				sph->setPointMask(CS_LBTNDOWN | CS_MOUSEMOVE);
			}
			m_secondPt = ucspt;
			showRubberLine(true);
			setRubberLineP2(m_secondPt);
			if (cs != CS_MOUSEMOVE)
			{
				prompt(5, tr("指定圆弧的终点或 [角度(A)]"));
			}
		}
		return;
	}
	//start - center - end
	if (status() == 5)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_endPt = ucspt;
			//设置橡皮筋
			setRubberLineP1(m_secondPt);
			setRubberLineP2(m_endPt);

			CDblPoint endPt = getPtOnArc(m_endPt, m_secondPt);
			CArc2 arc({ m_startPt.x(),m_startPt.y(),0 }, { m_secondPt.x(),m_secondPt.y(),0 }, endPt, 0);
			m_arc->set(osg::Vec3d(arc.center.x, arc.center.y, 0), arc.radius, arc.StartAngle(), arc.EndAngle());
			if (cs != CS_MOUSEMOVE)
			{
				drawFinished(scene);
			}
		}
		else if (rawInput == QString("A") || rawInput == QString("a"))
		{
			prompt(6, tr("指定包含角:"));
		}
		return;
	}
	//start - center - sweep angle
	if (status() == 6)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_endPt = ucspt;
			//设置橡皮筋
			setRubberLineP1(m_secondPt);
			setRubberLineP2(m_endPt);

			CArc2 arc;
			arc.center = { m_secondPt.x(),m_secondPt.y(),0 };
			const CDblPoint startPt = { m_startPt.x(),m_startPt.y(),0 };
			double startAngle = arc.GetSweepAngle(startPt);
			double sweepAngle = 2 * M_PI + arc.GetSweepAngle({ m_endPt.x(),m_endPt.y(),0 });
			const double radius = CLine2(startPt, arc.center).Length();
			arc.Set(arc.center, radius, startAngle, sweepAngle);
			m_arc->set(osg::Vec3d(arc.center.x, arc.center.y, 0), arc.radius, arc.StartAngle(), arc.EndAngle());
			if (cs != CS_MOUSEMOVE)
			{
				drawFinished(scene);
			}
		}
		else if (data.type() == QVariant::Double)
		{
			double angle = data.value<double>();
			double sweepAngle = angle * M_PI / 180;
			const CDblPoint startPt = { m_startPt.x(),m_startPt.y(),0 };
			const CDblPoint center = { m_secondPt.x(),m_secondPt.y(),0 };
			CArc2 arc;
			arc.center = center;
			double startAngle = arc.GetSweepAngle(startPt);
			const double radius = CLine2(startPt, center).Length();
			arc.Set(center, radius, startAngle, sweepAngle);

			m_arc->set(osg::Vec3d(arc.center.x, arc.center.y, 0), arc.radius, arc.StartAngle(), arc.EndAngle());
			drawFinished(scene);
			return;
		}
		return;
	}
	//start - end
	if (status() == 7)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			if (sph)
			{
				sph->setPointMask(CS_LBTNDOWN | CS_MOUSEMOVE);
			}
			m_secondPt = ucspt;
			showRubberLine(true);
			setRubberLineP2(m_secondPt);
			if(cs != CS_MOUSEMOVE)
			{
				prompt(8, tr("指定圆弧的中心或 [角度(A)/方向(D)/半径(R)]:"));
			}
		}
		return;
	}
	//start - end - center
	if (status() == 8)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_endPt = ucspt;
			//设置橡皮筋
			setRubberLineP1(m_secondPt);
			setRubberLineP2(m_endPt);

			CDblPoint endPt = getPtOnArc(m_secondPt, m_endPt);
			CArc2 arc({ m_startPt.x(),m_startPt.y(),0 }, { m_endPt.x(),m_endPt.y(),0 }, endPt, 0);

			m_arc->set(osg::Vec3d(arc.center.x, arc.center.y, 0), arc.radius, arc.StartAngle(), arc.EndAngle());
			if(cs != CS_MOUSEMOVE)
			{
				drawFinished(scene);
				return;
			}
		}
		else if (rawInput == QString("A") || rawInput == QString("a"))
		{
			prompt(9, tr("指定包含角:"));
		}
		else if (rawInput == QString("D") || rawInput == QString("d"))
		{
			prompt(10, tr("指定圆弧起点处的切线方向:"));
		}
		else if (rawInput == QString("R") || rawInput == QString("r"))
		{
			prompt(11, tr("指定圆弧半径:"));
		}
		return;
	}
	//start - end - sweep angle
	if (status() == 9)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_endPt = ucspt;
			//设置橡皮筋
			setRubberLineP1(m_secondPt);
			setRubberLineP2(m_endPt);

			CArc2 arc;
			arc.center = { m_secondPt.x(),m_secondPt.y(),0 };
			double sweepAngle = 2 * M_PI + arc.GetSweepAngle({ m_endPt.x(),m_endPt.y(),0 });

			CArc2 arc2(sweepAngle, { m_startPt.x(),m_startPt.y(),0 }, arc.center, 0);
			m_arc->set(osg::Vec3d(arc2.center.x, arc2.center.y, 0), arc2.radius, arc2.StartAngle(), arc2.EndAngle());
			if (cs != CS_MOUSEMOVE)
			{
				drawFinished(scene);
				return;
			}
		}
		else if(data.type() == QVariant::Double)
		{
			double angle = data.value<double>();
			double sweepAngle = angle * M_PI / 180;
			CArc2 arc(sweepAngle, { m_startPt.x(),m_startPt.y(),0 }, { m_secondPt.x(),m_secondPt.y(),0 }, 0);
			m_arc->set(osg::Vec3d(arc.center.x, arc.center.y, 0), arc.radius, arc.StartAngle(), arc.EndAngle());
			drawFinished(scene);
			return;
		}
	}
	//start - end - direction
	if (status() == 10)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_endPt = ucspt;
			//设置橡皮筋
			setRubberLineP2(m_endPt);
			const osg::Vec3d direction = m_endPt - m_startPt;
			CArc2 arc({ m_startPt.x(),m_startPt.y(),0 }, { m_secondPt.x(),m_secondPt.y(),0 }, CDblSize(direction.x(), direction.y()));
			m_arc->set(osg::Vec3d(arc.center.x, arc.center.y, 0), arc.radius, arc.StartAngle(), arc.EndAngle());
			if (cs != CS_MOUSEMOVE)
			{
				drawFinished(scene);
				return;
			}
		}
	}
	//start - end - radius
	if (status() == 11)
	{
		osg::Vec3d ucspt;
		if (getPoint2D(*ucs, data, rawInput, cs, ucspt))
		{
			m_endPt = ucspt;
			//设置橡皮筋
			setRubberLineP1(m_secondPt);
			setRubberLineP2(m_endPt);

			const CDblPoint startPt = { m_startPt.x(),m_startPt.y(),0 };
			const CDblPoint endPt = { m_secondPt.x(),m_secondPt.y(),0 };
			const double radius = CLine2({ m_endPt.x(),m_endPt.y(),0 }, endPt).Length();
			CArc2 arc(startPt, endPt, radius, 0);
			m_arc->set(osg::Vec3d(arc.center.x, arc.center.y, 0), arc.radius, arc.StartAngle(), arc.EndAngle());
			if (cs != CS_MOUSEMOVE)
			{
				drawFinished(scene);
				return;
			}
		}
		else if (data.type() == QVariant::Double)
		{
			const double radius = data.value<double>();
			CArc2 arc({ m_startPt.x(),m_startPt.y(),0 }, { m_secondPt.x(),m_secondPt.y(),0 }, radius, 0);
			m_arc->set(osg::Vec3d(arc.center.x, arc.center.y, 0), arc.radius, arc.StartAngle(), arc.EndAngle());
			drawFinished(scene);
			return;
		}
	}
}

void Arc2DHandler::drawFinished(Scene * scene)
{
	auto undoStack = scene->undoStack();
	std::set<std::shared_ptr<INode>> children;
	children.insert(m_arc);
	undoStack->push(new OpAdd(children));
	emit finished();
}

CDblPoint Arc2DHandler::getPtOnArc(const osg::Vec3d & Pt, const osg::Vec3d & center)
{
	CArc2 arc;
	arc.center = { center.x(),center.y(),0 };
	double endAngle = arc.GetSweepAngle({ Pt.x(),Pt.y(),0 });
	const double detX = m_startPt.x() - center.x();
	const double detY = m_startPt.y() - center.y();
	const double radius = sqrt(detX*detX + detY * detY);
	return CDblPoint(arc.center.x + radius * cos(endAngle), arc.center.y + radius * sin(endAngle));
}

